package com.flow.module.sys.service.impl;

import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import org.activiti.bpmn.model.BpmnModel;
import org.activiti.engine.HistoryService;
import org.activiti.engine.ManagementService;
import org.activiti.engine.RepositoryService;
import org.activiti.engine.RuntimeService;
import org.activiti.engine.history.HistoricActivityInstance;
import org.activiti.engine.history.HistoricProcessInstance;
import org.activiti.engine.impl.RepositoryServiceImpl;
import org.activiti.engine.impl.TaskServiceImpl;
import org.activiti.engine.impl.context.Context;
import org.activiti.engine.impl.interceptor.Command;
import org.activiti.engine.impl.interceptor.CommandContext;
import org.activiti.engine.impl.persistence.entity.ExecutionEntity;
import org.activiti.engine.impl.persistence.entity.ProcessDefinitionEntity;
import org.activiti.engine.impl.persistence.entity.TaskEntity;
import org.activiti.engine.impl.pvm.PvmTransition;
import org.activiti.engine.impl.pvm.process.ActivityImpl;
import org.activiti.engine.impl.pvm.process.ProcessDefinitionImpl;
import org.activiti.engine.repository.ProcessDefinition;
import org.activiti.engine.runtime.ProcessInstance;
import org.activiti.engine.task.Comment;
import org.activiti.engine.task.Task;
import org.activiti.image.impl.DefaultProcessDiagramGenerator;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import com.flow.module.process.service.impl.BizApplySimpleServiceImpl;
import com.flow.module.sys.service.FlowProcessService;
import com.flow.module.sys.service.FlowTaskService;
import com.system.handle.model.ResponseFrame;

/**
 * 流程的Service
 * @author autoCode
 * @date 2017-12-29 10:12:19
 * @version V1.0.0
 */
@Component
public class FlowProcessServiceImpl implements FlowProcessService {

	private static final Logger LOGGER = LoggerFactory.getLogger(BizApplySimpleServiceImpl.class);
	@Autowired
	private RuntimeService runtimeService;
	@Autowired
	private FlowTaskService flowTaskService;

	@Autowired
	private HistoryService historyService;
	@Autowired
	private RepositoryService repositoryService;
	@Autowired
	private TaskServiceImpl taskServiceImpl;
	@Autowired
	private ManagementService managementService;

	@Override
	public ResponseFrame start(String processKey,
			Map<String, Object> params) {
		LOGGER.info("启动流程实例: " + processKey);
		ResponseFrame frame = new ResponseFrame();
		runtimeService.startProcessInstanceByKey(processKey, params);
		frame.setSucc();
		return frame;
	}

	@Override
	public ResponseFrame suspend(String processInstanceId) {
		LOGGER.info("暂停流程实例: " + processInstanceId);
		ResponseFrame frame = new ResponseFrame();
		if(!isSuspend(processInstanceId)) {
			//挂起该流程实例。也就是冻结暂停。也可激活
			runtimeService.suspendProcessInstanceById(processInstanceId);
		}
		frame.setSucc();
		return frame;
	}

	@Override
	public ProcessInstance getByProcessInstanceId(String processInstanceId) {
		return runtimeService
				.createProcessInstanceQuery()
				.processInstanceId(processInstanceId)
				.singleResult();
	}

	@Override
	public boolean isSuspend(String processInstanceId) {
		ProcessInstance pi = getByProcessInstanceId(processInstanceId);
		return pi.isSuspended();
	}

	@Override
	public ResponseFrame end(String processInstanceId,
			Map<String, Object> params) {
		LOGGER.info("结束流程实例: " + processInstanceId);
		ResponseFrame frame = new ResponseFrame();
		int num = flowTaskService.getCountByProcessInstanceId(processInstanceId);
		for (int i = 0; i < num; i ++) {
			Task task = flowTaskService.getByProcessInstanceId(processInstanceId);
			//处理会签结束的情况
			ProcessInstance pi = getByProcessInstanceId(processInstanceId);
			final String executionId = task.getExecutionId();
			// 直接跳转到结束
			String activityId = getEndEventActivityId(pi.getProcessDefinitionKey());
			taskServiceImpl.getCommandExecutor().execute(
					new Command<Comment>() {
						@Override
						public Comment execute(CommandContext commandContext) {
							//移除任务
							for (TaskEntity taskEntity : Context.getCommandContext().getTaskEntityManager().findTasksByExecutionId(executionId)) {
								Context.getCommandContext().getTaskEntityManager().deleteTask(taskEntity, "jump", false);
							}
							ExecutionEntity executionEntity = Context.getCommandContext().getExecutionEntityManager().findExecutionById(executionId);
							ProcessDefinitionImpl processDefinition = executionEntity.getProcessDefinition();
							ActivityImpl activity = processDefinition.findActivity(activityId);
							//设置为失败的终止
							executionEntity.setVariable("checkType", "fail");
							executionEntity.executeActivity(activity);
							return null;
						}
					});
		}
		frame.setSucc();
		return frame;
	}
	/**
	 * 获取结束节点的名称
	 * @param definitionKey
	 * @return
	 */
	private String getEndEventActivityId(String definitionKey) {
		String endActivityId = null;
		//List<ProcessDefinition> definitions = repositoryService.createProcessDefinitionQuery().processDefinitionKey(dkey).list();
		//ProcessDefinition definition = definitions.get(0);
		ProcessDefinition definition = repositoryService.createProcessDefinitionQuery().processDefinitionKey(definitionKey).latestVersion().singleResult();
		ProcessDefinitionEntity processDefinition = (ProcessDefinitionEntity) ((RepositoryServiceImpl) repositoryService)
				.getDeployedProcessDefinition(definition.getId());

		//获取所有的activity
		List<ActivityImpl> allActivities = processDefinition.getActivities();

		for(ActivityImpl activity : allActivities){
			String type = activity.getProperty("type").toString();
			if(type.equals("endEvent")){
				endActivityId = activity.getId();
				break;
			}
		}
		return endActivityId;
	}

	@Override
	public ProcessDefinition getProcDefByProcessInstanceId(
			String processInstanceId) {
		ProcessInstance pi = getByProcessInstanceId(processInstanceId);
		String procDefId = pi.getProcessDefinitionId();
		return repositoryService.createProcessDefinitionQuery().processDefinitionId(procDefId).singleResult();
	}

	@Override
	public InputStream diagramImg(String processInstanceId) {
		//ProcessDefinition procDef = getProcDefByProcessInstanceId(processInstanceId);
		//String diagramResourceName = procDef.getDiagramResourceName();
		//InputStream imageStream = repositoryService.getResourceAsStream(procDef.getDeploymentId(), diagramResourceName);

		ProcessDefinitionEntity processDefinitionEntity = getProcDefEntityByProcessInstanceId(processInstanceId);


		List<String> activeActivityIds = new ArrayList<String>(0);
		// 已执行完的任务节点  
		List<HistoricActivityInstance> finishedInstances = historyService.createHistoricActivityInstanceQuery().processInstanceId(processInstanceId).finished().list();
		for (HistoricActivityInstance hai : finishedInstances) {
			activeActivityIds.add(hai.getActivityId());
		}



		BpmnModel bpmnModel = repositoryService.getBpmnModel(processDefinitionEntity.getId());
		List<String> highLightedFlows = getHighLightedFlows(processInstanceId, processDefinitionEntity);
		InputStream imageStream = new DefaultProcessDiagramGenerator().generateDiagram(bpmnModel, "png",
				activeActivityIds,
				highLightedFlows, "宋体", "宋体",null, 1.0);


		/*InputStream imageStream = processEngine.getProcessEngineConfiguration().getProcessDiagramGenerator()
				.generateDiagram(bpmnModel, "png", activeActivityIds, new ArrayList(),
						processEngineConfiguration.getActivityFontName(),
						processEngineConfiguration.getLabelFontName(), null, 1.0);*/
		return imageStream;
	}

	@Override
	public ProcessDefinitionEntity getProcDefEntityByProcessInstanceId(String processInstanceId) {
		HistoricProcessInstance historicProcessInstance = historyService
				.createHistoricProcessInstanceQuery()
				.processInstanceId(processInstanceId).singleResult();
		return (ProcessDefinitionEntity) ((RepositoryServiceImpl) repositoryService)
				.getDeployedProcessDefinition(historicProcessInstance
						.getProcessDefinitionId());
	}

	/**
	 * 获取审批过的箭头
	 * @param processInstanceId
	 * @param processDefinitionEntity
	 * @return
	 */
	private List<String> getHighLightedFlows(String processInstanceId, ProcessDefinitionEntity processDefinitionEntity) {
		//获取流程走过的节点，并按照节点生成先 后顺序排序
		List<HistoricActivityInstance> historicActivityInstances = historyService
				.createHistoricActivityInstanceQuery()
				.processInstanceId(processInstanceId)
				.orderByHistoricActivityInstanceId().asc()
				.list();

		List<String> highFlows = new ArrayList<String>();
		// 用 以保存高亮的线flowId
		for (int i = 0; i < historicActivityInstances.size()  - 1; i++) {
			// 对历史流程节点进行遍历
			ActivityImpl activityImpl = processDefinitionEntity
					.findActivity(historicActivityInstances.get(i)
							.getActivityId());
			// 得到节点定义的详细 信息
			List<ActivityImpl> sameStartTimeNodes = new  ArrayList<ActivityImpl>();
			// 用以保存后需开始时间相同的节点
			ActivityImpl sameActivityImpl1 = processDefinitionEntity
					.findActivity(historicActivityInstances.get(i + 1)
							.getActivityId());
			// 将后面第一个节点放 在时间相同节点的集合里
			sameStartTimeNodes.add(sameActivityImpl1);
			for (int j = i + 1; j <  historicActivityInstances.size() - 1; j++) {
				HistoricActivityInstance activityImpl1 = historicActivityInstances
						.get(j);
				// 后续第一个节点
				HistoricActivityInstance activityImpl2 = historicActivityInstances
						.get(j + 1);
				// 后续第二个节点
				if (activityImpl1.getStartTime().equals(activityImpl2.getStartTime())) {
					// 如果第 一个节点和第二个节点开始时间相同保存
					ActivityImpl sameActivityImpl2 = processDefinitionEntity
							.findActivity(activityImpl2.getActivityId());
					sameStartTimeNodes.add(sameActivityImpl2);
				} else {
					// 有不相同跳出循环
					break;
				}
			}
			List<PvmTransition> pvmTransitions = activityImpl
					.getOutgoingTransitions();
			// 取出节点的所有出 去的线
			for (PvmTransition pvmTransition : pvmTransitions)  {
				// 对所有的线进行遍历
				ActivityImpl pvmActivityImpl = (ActivityImpl) pvmTransition
						.getDestination();
				// 如果取出的线的目标节点 存在时间相同的节点里，保存该线的id，进行高亮显示
				if  (sameStartTimeNodes.contains(pvmActivityImpl)) {
					highFlows.add(pvmTransition.getId());
				}
			}
		}
		return highFlows;
	}


}